//While this code is technically reusable, it is incredibly buggy and crash-prone, so I don't really recommend it.


local function CrossProduct(a, b)
	local c = {
		x = FixedMul(a.y, b.z) - FixedMul(a.z, b.y),
		y = FixedMul(a.z, b.x) - FixedMul(a.x, b.z),
		z = FixedMul(a.x, b.y) - FixedMul(a.y, b.x)
	}
	return c
end

local function VecDiv(a, b) 
	local c = {
		x = FixedDiv(a.x, b),
		y = FixedDiv(a.y, b),
		z = FixedDiv(a.z, b),
	}
	return c
end
//Code shamelessly stolen from p-slopes.c in the basegame
local function GetExtent(line, sector) 
	
	local fardist = -FRACUNIT
	local farmpdist = -FRACUNIT
	local farline
	
	for i = 0, #sector.lines-1
		local li = sector.lines[i]
		local tempx
		local tempy
		local dist
		local mpdist 

		if(li == line) then
			continue
		end

		tempx, tempy = P_ClosestPointOnLine(li.v1.x, li.v1.y, line)
		dist = R_PointToDist2(tempx, tempy, li.v1.x, li.v1.y)
		if (dist >= fardist) then
			fardist = dist
		end

		
		tempx, tempy = P_ClosestPointOnLine(li.v2.x, li.v2.y, line)
		dist = R_PointToDist2(tempx, tempy, li.v2.x, li.v2.y)
		if (dist >= fardist) then
			fardist = dist
		end
		
		
		tempx, tempy = P_ClosestPointOnLine((li.v1.x+li.v2.x)/2, (li.v1.y+li.v2.y)/2, line)
		mpdist = R_PointToDist2(tempx, tempy, (li.v1.x+li.v2.x)/2, (li.v1.y+li.v2.y)/2)
		if (mpdist > farmpdist) then
			farmpdist = mpdist
			farline = li
		end
		
		
		
	end
	return fardist, farline
end

//Code ported from source with much greater difficulty
local function ReconfigureViaVertices(slope, v1, v2, v3)
	slope.o = v1
	
	local vec1 = {x = v2.x-v1.x, y = v2.y-v1.y, z= v2.z-v1.z}
	local vec2 = {x = v3.x-v1.x, y = v3.y-v1.y, z= v3.z-v1.z}
	
	if (vec1.z == 0 and vec2.z == 0) then
		slope.zangle = 0
		slope.xydirection = 0
	end
	
	local m = max(
		max(max(abs(vec1.x), abs(vec1.y)), abs(vec1.z)),
		max(max(abs(vec2.x), abs(vec2.y)), abs(vec2.z))
		) >> 6
	
	local nvec1 = VecDiv(vec1, m)
	local nvec2 = VecDiv(vec2, m)
	local normal = CrossProduct(nvec1, nvec2)
	
	m = R_PointToDist2(0, 0, R_PointToDist2(0, 0, normal.x, normal.y), normal.z)
	
	if (normal.z < 0) then
		m = -$
	end
	//normal = VecDiv(normal, m)
	m = FixedHypot(normal.x, normal.y)
	
	local d = {
		x = -FixedDiv(normal.x, m),
		y = -FixedDiv(normal.y, m)
	}
	
	if (normal.z == 0) then
		normal.z = 1
	end
	
	slope.zdelta = FixedDiv(m, normal.z)
	slope.xydirection = R_PointToAngle2(0, 0, d.x, d.y)+ANGLE_180
	

end

//Code shamlessly stolen from the internet
local function FindIntersection (s1, e1, s2, e2)
  local d = (s1.x - e1.x) * (s2.y - e2.y) - (s1.y - e1.y) * (s2.x - e2.x)
  local a = s1.x * e1.y - s1.y * e1.x
  local b = s2.x * e2.y - s2.y * e2.x
  local x = (a * (s2.x - e2.x) - (s1.x - e1.x) * b) / d
  local y = (a * (s2.y - e2.y) - (s1.y - e1.y) * b) / d
  return x, y
end

local function FindSlopeLinedef(sector)


	for i = 0, #sector.lines-1
		local line = sector.lines[i]
		if (line.frontsector == sector) then
			if (line.special >= 700) and (line.special <= 705) then
				return line
			end
		else
			if (line.special >= 710) and (line.special <= 715) then
				return line
			end
		
		end
	
	end

end


local function ReorientSlope(slope, line, sector, oldExtent)
	local extent = GetExtent(line, sector)
	local normalzDelta = FixedDiv(slope.zdelta, oldExtent)
	normalzDelta  = FixedMul(slope.zdelta, oldExtent)
	
	local newOrigin = {
	x =(line.v1.x+line.v2.x)/2,
	y =(line.v1.y+line.v2.y)/2,
	z = slope.o.z
	}
	slope.o = newOrigin
	slope.zdelta = FixedDiv(normalzDelta, extent)
	slope.xydirection = R_PointToAngle2(line.v1.x, line.v1.y, line.v2.x, line.v2.y)+ANGLE_90
	
end

local function FindBankSlopeVertices(slope, line, backheight, frontheight, flooroffset)
	local extent, farline = GetExtent(line, line.frontsector)	
	local slopevertex = nil
	for mapthing in mapthings.iterate do 
		if (mapthing.type == 750) then
			if (mapthing.angle == line.tag) then
				slopevertex = mapthing
			end
		end
	end
	local v3 = {}
	if (slopevertex)
		v3  = {x = slopevertex.x*FRACUNIT, y = slopevertex.y*FRACUNIT, z = (slopevertex.z*FRACUNIT)-flooroffset}
	else
		local l1s = {x = line.v1.x/FRACUNIT, y= line.v1.y/FRACUNIT}
		local l1e = {x = line.v2.x/FRACUNIT, y= line.v2.y/FRACUNIT}
		local l2s = {x = farline.v1.x/FRACUNIT, y= farline.v1.y/FRACUNIT}
		local l2e = {x = farline.v2.x/FRACUNIT, y= farline.v2.y/FRACUNIT}
		local v3x, v3y = FindIntersection(l1s, l1e, l2s, l2e)
		v3 = {x = v3x*FRACUNIT, y = v3y*FRACUNIT, z = backheight}		
	end
	
	local v1vert
	local dist1 = R_PointToDist2(v3.x, v3.y, line.v1.x, line.v1.y)
	local dist2 = R_PointToDist2(v3.x, v3.y, line.v2.x, line.v2.y)
	if (dist1 > dist2) then
		v1vert = line.v1
	else
		v1vert = line.v2
	end
	
	local v2vert
	dist1 = R_PointToDist2(v3.x, v3.y, farline.v1.x, farline.v1.y)
	dist2 = R_PointToDist2(v3.x, v3.y, farline.v2.x, farline.v2.y)
	if (dist1 > dist2) then
		v2vert = farline.v1
	else
		v2vert = farline.v2
	end



	local v1 = {x = v1vert.x, y = v1vert.y, z = backheight}
	local v2 = {x = v2vert.x, y = v2vert.y, z = frontheight}
	return v1, v2, v3
end

addHook("MapLoad", function(mapnum)
	if not mapheaderinfo[mapnum].slopetransforms then return end
	
	for line in lines.iterate do 
		//print("Special: " + line.special + ", Tag: " + line.tag)
		if (line.special == 740) then
			for fof in line.frontsector.ffloors()
				if (fof.t_slope) or (fof.b_slope) then
					local slopeLine = FindSlopeLinedef(fof.master.frontsector)
					local oldExtent = GetExtent(slopeLine, fof.master.frontsector)
					if (fof.t_slope) then
						if (line.flags & 8192)
							local v1, v2, v3 = FindBankSlopeVertices(fof.t_slope, line, slopeLine.frontsector.ceilingheight, slopeLine.backsector.ceilingheight, 0)
							ReconfigureViaVertices(fof.t_slope, v1, v2, v3)
						else
							ReorientSlope(fof.t_slope, line, line.frontsector, oldExtent)
						end
					end
					if (fof.b_slope) then
						if (line.flags & 8192)
							local v1, v2, v3 = FindBankSlopeVertices(fof.b_slope, line, slopeLine.frontsector.floorheight, slopeLine.backsector.floorheight, (slopeLine.frontsector.ceilingheight-slopeLine.frontsector.floorheight))
							ReconfigureViaVertices(fof.b_slope, v1, v2, v3)
						else
							ReorientSlope(fof.b_slope, line, line.frontsector, oldExtent)
						end
					end
				end
			end
		end
		if (line.special == 700 and line.flags & 8192) then
			local v1, v2, v3 = FindBankSlopeVertices(line.frontsector.f_slope, line, line.backsector.floorheight, line.frontsector.floorheight, 0)
			ReconfigureViaVertices(line.frontsector.f_slope, v1, v2, v3)
		end
	end
	
	
					
end)


freeslot(
"MT_SLOPERING",
"S_SLOPERING0",
"S_SLOPERING1"
)



local function A_SpawnRingOnSlope(actor, var1, var2)
	P_TeleportMove(actor, actor.x, actor.y, actor.z)
	P_SpawnMobj(actor.x, actor.y, actor.floorz+(24*FRACUNIT), MT_RING)
	return
end

mobjinfo[MT_SLOPERING] = {
spawnstate = S_SLOPERING0,
reactiontime = 16,
speed = 10*FRACUNIT,
radius = 32*FRACUNIT,
height = 32*FRACUNIT,
damage = 3,
spawnhealth = 0,
dispoffset = 0,
doomednum = 1514,
flags = MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SCENERY|MF_NOCLIPHEIGHT
}


states[S_SLOPERING0] = {
sprite = SPR_NULL,
frame = A,
tics = 5,
nextstate = S_SLOPERING1
}
states[S_SLOPERING1] = {
sprite = SPR_NULL,
frame = A,
tics = 0,
action = A_SpawnRingOnSlope,
nextstate = S_NULL
}
